using System;
using System.Collections.Generic;
using System.Text;
using TuringMachine.StateAutomat;
using TuringMachine.CompilerModule;

namespace TuringMachine
{
    public class Controller
    {
        private Tape tape = null;
        private Automat stateAutomat = null;
        private TransactionTable transactionTable = null;
        private Compiler compiler = null;
        private string input;

        public Controller()
        {
            tape = new Tape("#",0);
            stateAutomat = new Automat();
            transactionTable = new TransactionTable();
            compiler = new Compiler(ref stateAutomat, ref transactionTable);
        }

        public string GetTapeString()
        {
            return tape.TapeInput;
        }

        public int GetTapeIndex()
        {
            return tape.Position;
        }

        public void SetTapeString(string input)
        {
            tape.TapeInput = input;
            this.input = input;
        }

        public string GetInput()
        {
            return this.input;
        }

        public void SetTapeIndex(UInt16 index)
        {
            tape.Position = index;
        }

        public void GetStatesList(ref int stepsCounter, ref List<string> stateNames)
        {
        }

        public string GetAutomatState()
        {
            return stateAutomat.CurrentState.Name;
            
        }

        public void MoveAutomatToStart()
        {
            stateAutomat.CurrentState = stateAutomat.GetStartState();
            this.SetTapeIndex(0);
        }

        public void Compile(string script)
        {
            string[] commandsArray = null;
            string[] delim = {"\n","\r","\r\n"};
            commandsArray = script.Split(delim, StringSplitOptions.RemoveEmptyEntries);
            compiler.CompileScript(commandsArray);
        }

        public string PerformStep()
        {
            char inputChar = tape.CurrentChar;
            StringBuilder _ret = new StringBuilder();
            //Gets current state in automat
            State fromState = stateAutomat.CurrentState;
            if (inputChar == ' ')
            {
                inputChar = '_';
            }
            _ret.AppendFormat("Automat in state '{0}'. Read '{1}'.", fromState.Name, inputChar);
            //Gets transaction
            //FromConfiguration fromConfiguration = new FromConfiguration(fromState, inputChar);
            FromConfiguration fromConfiguration = transactionTable.GetFromConfigurationInstance(fromState, inputChar);
            if (fromConfiguration == null)
            {
                ///TODO: Add stop
                throw new Exception ("There are no step from state " + fromState.Name + " for input "+inputChar.ToString());
            }
            ToConfiguration toConfiguration = transactionTable.GetToConfiguration(fromConfiguration);

            State toState = toConfiguration.PairState;
            char tapeAction = toConfiguration.PairChar;

            //Move automat
            stateAutomat.CurrentState = toState;
            _ret.AppendFormat("Move to state '{0}'.", toState.Name);
            //Perform tape action
            switch (tapeAction)
            {
                case('>'):
                    tape.MoveRight();
                    _ret.Append("Move right on tape");
                    break;
                case('<'):
                    tape.MoveLeft();
                    _ret.Append("Move left on tape");
                    break;
                case('_'):
                    tape.CurrentChar = ' ';
                    _ret.AppendFormat("Write '{0}' to tape",tapeAction);
                    break;
                default:
                    tape.CurrentChar = tapeAction;
                    _ret.AppendFormat("Write '{0}' to tape", tapeAction);
                    break;
            }
            return _ret.ToString();

        }

        public bool IsStop(ref string reason)
        {
            bool _ret = true;
            
            switch (stateAutomat.CurrentState.Type)
            {

                case StateType.StartState:
                    _ret = false;
                    break;
                case StateType.MiddleState:
                    _ret = false;
                    break;
                case StateType.HaltState:
                    reason = "Automat entered to Halting state";
                    break;
                case StateType.YesState:
                    reason = "Automat entered to Yes state";
                    break;
                case StateType.NoState:
                    reason = "Automat entered to No state";
                    break;
                case StateType.UnknownState:
                    reason = "Automat entered to Unknown state";
                    break;
                default:
                    break;
            }
            return _ret;
        }

    }
}
